package com.tom.architect02.p4.day38.simple7.base;

import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;

/**
 * Added by Tom on 2024/01/29.
 */
public class BasePresenter<V extends BaseView, M extends BaseModel> {
    // 公用方法。传递进来的时候，会有不同的View。 只能使用[泛型]。
    private SoftReference<V> mViewReference; // WeakReference
    // private V mView; // 不是软引用，弱引用。
    private V mProxyView;
    // View 一般是Activity，涉及到内存泄漏，但是已经解绑，就不会涉及到泄漏问题。没解绑可能涉及内存泄漏。

    // 动态创建的model对象。
    private M mModel;

    public M getModel() {
        return mModel;
    }

    public void attach(V view) {
//        this.mView = view;
        this.mViewReference = new SoftReference<V>(view); // 弱应用的使用。
        // ~~~~~~用代理对象来实现~~~~~~ 动态代理实现AOP。
        this.mProxyView = (V) Proxy.newProxyInstance(view.getClass().getClassLoader(),
                view.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
                        // 每次执行这个方法，调用的是被代理的对象。
                        if (mViewReference == null || mViewReference.get() == null) { // 取弱引用。
                            return null;
                        }
                        // 没解绑执行的是原始被代理 View 的方法。 从而不要每次都判空。
                        // return method.invoke(mView, args);
                        return method.invoke(mViewReference.get(), args);
                    }
                });

        // 3.动态创建model，获取class通过反射获取。【Activity实例，View对象，都是通过反射创建的】
        // 3.1 获取class对象。
        Type getType = this.getClass().getGenericSuperclass();
        ParameterizedType parameterizedType2 = (ParameterizedType) getType;
        Type[] params = parameterizedType2.getActualTypeArguments();
        try {
            // 类型判断。第0个位置拿的是 V；第1个位置拿到的是 M.
            mModel = (M) ((Class) params[1]).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 解绑view，避免
    public void detach() {
        // 不解绑的话Activity 持有Presenter，presenter又持有了Activity，最终会导致内存泄漏。
        this.mViewReference.clear();
        this.mViewReference = null;
        // this.mView =null;
        // 注释掉。
//        this.mProxyView = null;
    }

    public V getView() {
        return mProxyView; // 返回代理对象。
    }
}

/**
 * GC回收算法：标记清除法。
 * 都是接口：通用代码 view!=null 统一处理。这个是 AOP 思想。aspectJ/ 动态代理。
 */